using System;
using System.Security.Cryptography;
using System.Text;
using System.IO;
using System.Web;

namespace SqlWebAdmin.CSharp
{
	/// <summary>
	/// Summary description for Encryption.
	/// </summary>
	public class Encryption
	{
		public static Encryption Current()
		{
			HttpContext ctx = HttpContext.Current;
			return Current(ctx.User.Identity.Name);
		}
		public static Encryption Current(string userName)
		{

			HttpContext ctx = HttpContext.Current;
			byte[] initvec = null;
			string iv = (string)ctx.Profile["InitializationVector"];
			if (iv == null || iv == "")
			{
				initvec = CreateIV();
				iv = Convert.ToBase64String(initvec);
				ctx.Profile["InitializationVector"] = iv;
			}
			else
			{
				initvec = Convert.FromBase64String(iv);
			}
			string cryptKey = string.Empty;
			if (userName.Length < 32)
			{
				int diff = 32 - userName.Length;
				// some quality gibberish
				string padding = "qxolqpadovyhnwduwqdwqbiqdcqed";
				cryptKey = userName + padding.Substring(0, diff);
			}
			else
				cryptKey = userName.Substring(0, 32);

			byte[] key = UnicodeEncoding.UTF8.GetBytes(cryptKey);

			return new Encryption(initvec, key);
		}
		public Encryption(byte[] initVector, byte[] privateKey)
		{

			//
			// TODO: Add constructor logic here
			//
			//           string foo = "thisisastring123";
			//            foo.Substring(
			eCryptn = new EncryptionProvider(initVector,privateKey);
		}
		private EncryptionProvider eCryptn;

		public string Encrypt(string toEncrypt)
		{
			return eCryptn.AESEncrypt(toEncrypt);

		}
		public string Decrypt(string cipher)
		{
			return eCryptn.AESDecrypt(cipher);
		}
		public static byte[] CreateIV()
		{
			return EncryptionProvider.CreateIV();
		}
		public string CreateSalt()
		{
			byte[] bytSalt = new byte[8];
			RNGCryptoServiceProvider rng;

			rng = new RNGCryptoServiceProvider();
			rng.GetBytes(bytSalt);
			return Convert.ToBase64String(bytSalt);
		}
	}
}

internal class EncryptionProvider
{
	private byte[] KeyValue;
	private byte[] IVValue;

	public EncryptionProvider(byte[] initVector, byte[] keyVal)
	{

		KeyValue = keyVal;
		IVValue = initVector;
	}

	// return encrypted data

	public static byte[] CreateIV()
	{
		RijndaelManaged aesMgd = new RijndaelManaged();
		aesMgd.GenerateIV();
		return aesMgd.IV;
	}

	protected byte[] Encrypt(string StringToEncrypt)
	{
        MemoryStream ms = null;
        CryptoStream cs = null;

        try
        {

            RijndaelManaged aesMgd = new RijndaelManaged();
            aesMgd.IV = this.IVValue;
            aesMgd.Key = this.KeyValue;

            byte[] inputByteArray = Encoding.UTF8.GetBytes(StringToEncrypt);
            ms = new MemoryStream();

            cs = new CryptoStream(ms, aesMgd.CreateEncryptor(), CryptoStreamMode.Write);
            cs.Write(inputByteArray, 0, inputByteArray.Length);
            cs.FlushFinalBlock();
            return ms.ToArray();
        }
        catch (Exception e)
        {
            throw new InvalidOperationException(Resources.Errors.CouldNotDecrypt, e);
        }
        finally
        {
            if (cs != null)
                cs.Dispose();

            if (ms != null)
                ms.Dispose();
        }
	}

	protected string Decrypt(byte[] inputByteArray)
	{
        CryptoStream cs = null;
        MemoryStream ms = null;
        try
        {

            RijndaelManaged aesMgd = new RijndaelManaged();
            aesMgd.IV = this.IVValue;
            aesMgd.Key = this.KeyValue;

            ms = new MemoryStream();
            cs = new CryptoStream(ms, aesMgd.CreateDecryptor(),
                CryptoStreamMode.Write);
            cs.Write(inputByteArray, 0, inputByteArray.Length);
            cs.FlushFinalBlock();
            //construct the string
            byte[] DecryptedArray = ms.ToArray();
            Char[] characters;// = new Char[60];
            Decoder dec = Encoding.UTF8.GetDecoder();
            int charlen = dec.GetCharCount(DecryptedArray, 0, DecryptedArray.Length);
            characters = new Char[charlen];
            charlen =
                dec.GetChars(DecryptedArray, 0, DecryptedArray.Length, characters, 0);
            string DecrpytedString = new string(characters, 0, charlen);
            return DecrpytedString;
        }
        catch (Exception e)
        {

            throw new InvalidOperationException(Resources.Errors.CouldNotDecrypt, e);
        }
        finally
        {
            if (cs != null)
                cs.Dispose();

            if (ms != null)
                ms.Dispose();
        }
	}

	public string AESEncrypt(string cleartext)
	{
		return EncryptedBytesToString(Encrypt(cleartext));
	}

	public string AESDecrypt(string cipher)
	{
		return Decrypt(EncryptedStringToBytes(cipher));
	}

	public string EncryptedBytesToString(byte[] EncryptedArray)
	{
		return Convert.ToBase64String(EncryptedArray);
	}

	public byte[] EncryptedStringToBytes(string EncryptedString)
	{
		return Convert.FromBase64String(EncryptedString);
	}
}

